#include "ringbuf.h"
#include <string.h>

void ringbuf_init(ringbuf_t *rbuf, uint8_t *buf, uint32_t size)
{
    rbuf->data = buf;
    rbuf->size = size;
    rbuf->head = 0;
    rbuf->tail = 0;
    rbuf->flip = 0;

    memset(buf, 0, size);
}

uint32_t ringbuf_data_size(ringbuf_t *rbuf)
{
    if(rbuf->head > rbuf->tail)
    {
        return rbuf->head - rbuf->tail;
    }else if(rbuf->head < rbuf->tail)
    {
        return rbuf->size - (rbuf->tail - rbuf->head);
    }else
    {
        if(rbuf->flip)
            return rbuf->size;
        else
            return 0;
    }
}

uint32_t ringbuf_free_size(ringbuf_t *rbuf)
{
    return rbuf->size - ringbuf_data_size(rbuf);
}

uint32_t ringbuf_put(ringbuf_t *rbuf, uint8_t *buf, uint32_t num)
{
    uint32_t num1, num2;

    //Check free space
    num1 = ringbuf_free_size(rbuf);
    num = (num <= num1) ? num : num1;
    
    if (rbuf->head + num > rbuf->size)
    {
        num1 = rbuf->size - rbuf->head;
        num2 = num - num1;
    }else
    {
        num1 = num;
        num2 = 0;
    }
    
    if (num1)
    {
        memcpy(rbuf->data + rbuf->head, buf, num1);
        rbuf->head += num1;
        if(rbuf->head >= rbuf->size)
        {
            rbuf->head = 0;
            rbuf->flip = !rbuf->flip;
        }
    }
    
    if(num2)
    {
        memcpy(rbuf->data + rbuf->head, buf + num1, num2);
        rbuf->head += num2;
    }
    
    return num;
}

uint32_t ringbuf_get(ringbuf_t *rbuf, uint8_t *buf, uint32_t num)
{
    uint32_t num1, num2;
    
    //Check data size
    num1 = ringbuf_data_size(rbuf);
    num = (num <= num1) ? num : num1;

    if (rbuf->tail + num > rbuf->size)
    {
        num1 = rbuf->size - rbuf->tail;
        num2 = num - num1;
    }else
    {
        num1 = num;
        num2 = 0;
    }
    
    if(num1)
    {
        memcpy(buf, rbuf->data + rbuf->tail, num1);
        rbuf->tail += num1;
        if(rbuf->tail >= rbuf->size)
        {
            rbuf->tail = 0;
            rbuf->flip = !rbuf->flip;
        }
    }
    
    if(num2)
    {
        memcpy(buf + num1, rbuf->data + rbuf->tail, num2);
        rbuf->tail += num2;
    }
    
    return num;
}
